package com.coisshi.base.module.oss.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.coisshi.base.common.exception.BizException;
import com.coisshi.base.framework.config.properties.CloudStorageProperties;
import com.coisshi.base.framework.config.properties.TencentCosProperties;
import com.coisshi.base.module.oss.service.CloudStorageService;
import com.coisshi.base.module.oss.util.CloudStorageUtil;
import com.coisshi.base.module.oss.vo.OssPolicyResultVo;
import com.qcloud.cos.COSClient;
import com.qcloud.cos.exception.CosClientException;
import com.qcloud.cos.model.CannedAccessControlList;
import com.qcloud.cos.model.ObjectMetadata;
import com.qcloud.cos.model.PutObjectRequest;
import com.qcloud.cos.model.PutObjectResult;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Base64;
import java.util.Date;

@Slf4j
@Service
@RequiredArgsConstructor
public class TencentCosServiceImpl implements CloudStorageService {
    private final COSClient cosClient;
    private final CloudStorageProperties cloudStorageProperties;

    @Override
    public OssPolicyResultVo getPolicy(String dirPrefix) {
        TencentCosProperties cosProperties = cloudStorageProperties.getTencent();
        OssPolicyResultVo vo = new OssPolicyResultVo();
        
        // 设置基本信息
        vo.setAccessKeyId(cosProperties.getSecretId());
        String dir = cosProperties.getDir() + (dirPrefix != null ? dirPrefix : "");
        vo.setDir(dir);
        vo.setHost(generateFileHost(cosProperties));
        
        // 设置过期时间（5分钟后）
        long expireTime = System.currentTimeMillis() / 1000 + 300;
        vo.setExpire(String.valueOf(expireTime));
        
        try {
            // 生成策略
            JSONObject policy = new JSONObject();
            policy.put("expiration", new Date(expireTime * 1000));
            
            JSONObject conditions = new JSONObject();
            conditions.put("bucket", cosProperties.getBucket());
            conditions.put("q-sign-algorithm", "sha1");
            conditions.put("q-ak", cosProperties.getSecretId());
            conditions.put("q-sign-time", System.currentTimeMillis()/1000 + ";" + expireTime);
            
            // 添加文件大小限制条件（0-1GB）
            conditions.put("content-length-range", Arrays.asList(0, 1024 * 1024 * 1024));
            
            // 添加目录前缀限制
            if (StringUtils.hasText(dir)) {
                conditions.put("key", dir + "${filename}");
            }
            
            policy.put("conditions", conditions);
            
            // 生成 policy 字符串
            String policyStr = Base64.getEncoder().encodeToString(policy.toString().getBytes(StandardCharsets.UTF_8));
            vo.setPolicy(policyStr);
            
            // 生成签名
            String signKey = hmacSha1(cosProperties.getSecretKey(), String.valueOf(expireTime));
            String stringToSign = policyStr + "\n" + signKey;
            String signature = hmacSha1(cosProperties.getSecretKey(), stringToSign);
            vo.setSignature(signature);
            
            return vo;
        } catch (Exception e) {
            log.error("生成腾讯云COS上传策略失败: {}", e.getMessage(), e);
            throw new BizException("生成上传策略失败：" + e.getMessage());
        }
    }

    @Override
    public String uploadFile(MultipartFile file, String objectName) throws BizException {
        TencentCosProperties cosProperties = cloudStorageProperties.getTencent();
        if (file == null || file.isEmpty()) {
            throw new BizException("上传文件不能为空");
        }
        if (!StringUtils.hasText(objectName)) {
            objectName = CloudStorageUtil.generateStructuredObjectName(
                    cosProperties.getDir(), file.getOriginalFilename(), file.getContentType());
        }
        try {
            return uploadFile(file.getInputStream(), objectName);
        } catch (IOException e) {
            log.error("读取上传文件失败: {}", e.getMessage(), e);
            throw new BizException("读取上传文件失败：" + e.getMessage());
        }
    }

    @Override
    public String uploadFile(InputStream inputStream, String objectName) throws BizException {
        TencentCosProperties cosProperties = cloudStorageProperties.getTencent();
        if (inputStream == null) {
            throw new BizException("上传文件流不能为空");
        }
        if (!StringUtils.hasText(objectName)) {
            throw new BizException("对象名称不能为空");
        }
        try {
            ObjectMetadata metadata = new ObjectMetadata();
            PutObjectRequest putObjectRequest = new PutObjectRequest(
                    cosProperties.getBucket(), objectName, inputStream, metadata);
            putObjectRequest.setCannedAcl(CannedAccessControlList.PublicRead);
            PutObjectResult result = cosClient.putObject(putObjectRequest);
            log.info("腾讯云COS文件上传成功, ETag: {}, objectName: {}", result.getETag(), objectName);
            return generateFileUrl(objectName, cosProperties);
        } catch (CosClientException e) {
            log.error("腾讯云COS上传失败: {}", e.getMessage(), e);
            throw new BizException("文件上传到腾讯云COS失败: " + e.getMessage());
        } catch (Exception e) {
            log.error("腾讯云COS上传发生未知错误: {}", e.getMessage(), e);
            throw new BizException("文件上传失败，请稍后重试");
        }
    }

    @Override
    public void deleteFile(String objectName) throws BizException {
        TencentCosProperties cosProperties = cloudStorageProperties.getTencent();
        if (!StringUtils.hasText(objectName)) {
            throw new BizException("删除的对象名称不能为空");
        }
        try {
            cosClient.deleteObject(cosProperties.getBucket(), objectName);
            log.info("腾讯云COS文件删除成功, objectName: {}", objectName);
        } catch (CosClientException e) {
            log.error("腾讯云COS删除文件失败: {}", e.getMessage(), e);
            throw new BizException("删除腾讯云COS文件失败: " + e.getMessage());
        } catch (Exception e) {
            log.error("腾讯云COS删除文件发生未知错误: {}", e.getMessage(), e);
            throw new BizException("删除文件失败，请稍后重试");
        }
    }

    private String generateFileUrl(String objectName, TencentCosProperties cosProperties) {
        // 腾讯云COS访问URL格式：https://<bucket>.cos.<region>.myqcloud.com/<objectName>
        return String.format("https://%s.cos.%s.myqcloud.com/%s",
                cosProperties.getBucket(), cosProperties.getRegion(), objectName);
    }

    private String generateFileHost(TencentCosProperties cosProperties) {
        return String.format("https://%s.cos.%s.myqcloud.com/",
                cosProperties.getBucket(), cosProperties.getRegion());
    }

    /**
     * 使用 HMAC-SHA1 算法生成签名
     */
    private String hmacSha1(String key, String data) throws Exception {
        Mac mac = Mac.getInstance("HmacSHA1");
        SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), mac.getAlgorithm());
        mac.init(secretKeySpec);
        byte[] hash = mac.doFinal(data.getBytes(StandardCharsets.UTF_8));
        return Base64.getEncoder().encodeToString(hash);
    }
} 